{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "oof_train = np.loadtxt('data/model_save/train_bert_prob_0.8977973628929045.txt') # 0.bert_0.8977973628929045.csv\n",
    "oof_test = np.loadtxt('data/model_save/test_bert_prob_0.8977973628929045.txt') #  bert_0.0.0.7308399121801145"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 113,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# train['情感倾向'] = np.argmax(oof_train, axis=1) - 1\n",
    "# train.to_csv('data/train_presto.csv', index=)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "train = pd.read_csv('data/nCoV_100k_train.labled.csv',header=0)\n",
    "# train = pd.read_csv('data/new_train.csv')\n",
    "test = pd.read_csv('data/nCov_10k_test.csv',header=0)\n",
    "train = train[(train['情感倾向'].isin(['-1','0','1']))]\n",
    "train = train[~train.index.isin(['35202','41624','33936'])].reset_index(drop=True)\n",
    "labels = train['情感倾向'].astype('int').values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1.06643358 0.93466748 1.06549164]\n"
     ]
    }
   ],
   "source": [
    "train_y = labels+1\n",
    "optR = OptimizedRounder()\n",
    "optR.fit(oof_train, train_y)\n",
    "coefficients = optR.coefficients()\n",
    "print(coefficients)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.7225638338130592"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "oof_train2 = coefficients * oof_train\n",
    "cv_score = f1_score(train_y, np.argmax(oof_train, axis=-1), average='macro')\n",
    "cv_score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.7233132140763497"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# f1_score(train_y, np.argmax(oof_train2, axis=-1), average='macro')\n",
    "cv_score = optR.predict(oof_train, train_y)\n",
    "cv_score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       " 0    0.5868\n",
       " 1    0.2452\n",
       "-1    0.1680\n",
       "Name: y, dtype: float64"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# coefficients = [1.11111411, 0.936682753, 0.96274868]\n",
    "oof_test2= oof_test * coefficients\n",
    "test['y'] = np.argmax(oof_test2, axis=1) - 1\n",
    "test['id'] = test['微博id'].copy()#map(lambda x: str(x)+' ')\n",
    "test['y'].value_counts(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       " 0    0.5759\n",
       " 1    0.2401\n",
       "-1    0.1840\n",
       "Name: y2, dtype: float64"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test2 = pd.read_csv('data/submit/bert_0.7328015743130485.csv')\n",
    "test['y2'] = test2['y']\n",
    "test[test['y'] == test['y2']].shape[0]/test.shape[0]\n",
    "test['y2'].value_counts(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.9294"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test[test['y'] == test['y2']].shape[0]/test.shape[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 133,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "np.savetxt('./data/model_save/train_bert_prob_{}.txt'.format(cv_score), oof_train2)\n",
    "np.savetxt('./data/model_save/test_bert_prob_{}.txt'.format(cv_score), oof_test2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "test[['id', 'y']].to_csv('./data/submit/bert_{}.csv'.format(cv_score), index=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 135,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.7233132140763497"
      ]
     },
     "execution_count": 135,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cv_score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# -*- coding: utf-8 -*-\n",
    "\"\"\"\n",
    "@Time ： 2020/3/15 22:59\n",
    "@Auth ： joleo\n",
    "@File ：optimized_rounder.py\n",
    "\"\"\"\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "from sklearn.metrics import f1_score\n",
    "from functools import partial\n",
    "import scipy as sp\n",
    "\n",
    "class OptimizedRounder(object):\n",
    "    \"\"\"\n",
    "    An optimizer for rounding thresholds\n",
    "    to maximize Quadratic Weighted Kappa (QWK) score\n",
    "    # https://www.kaggle.com/naveenasaithambi/optimizedrounder-improved\n",
    "    # https://www.kaggle.com/teejmahal20/regression-with-optimized-rounder\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(self):\n",
    "        self.coef_ = 0\n",
    "\n",
    "    def _macro_f1_score(y_true, y_pred, n_labels):\n",
    "        # https://www.kaggle.com/corochann/fast-macro-f1-computation\n",
    "        total_f1 = 0.\n",
    "        for i in range(n_labels):\n",
    "            yt = y_true == i\n",
    "            yp = y_pred == i\n",
    "\n",
    "            tp = np.sum(yt & yp)\n",
    "\n",
    "            tpfp = np.sum(yp)\n",
    "            tpfn = np.sum(yt)\n",
    "            if tpfp == 0:\n",
    "                print('[WARNING] F-score is ill-defined and being set to 0.0 in labels with no predicted samples.')\n",
    "                precision = 0.\n",
    "            else:\n",
    "                precision = tp / tpfp\n",
    "            if tpfn == 0:\n",
    "                print(f'[ERROR] label not found in y_true...')\n",
    "                recall = 0.\n",
    "            else:\n",
    "                recall = tp / tpfn\n",
    "            if precision == 0. or recall == 0.:\n",
    "                f1 = 0.\n",
    "            else:\n",
    "                f1 = 2 * precision * recall / (precision + recall)\n",
    "            total_f1 += f1\n",
    "        return total_f1 / n_labels\n",
    "\n",
    "    def _f1_loss(self, coef, X, y):\n",
    "        \"\"\"\n",
    "        Get loss according to\n",
    "        using current coefficients\n",
    "\n",
    "        :param coef: A list of coefficients that will be used for rounding\n",
    "        :param X: The raw predictions\n",
    "        :param y: The ground truth labels\n",
    "        \"\"\"\n",
    "        X_p = coef * np.copy(X)\n",
    "\n",
    "        return -f1_score(y, np.argmax(X_p, axis=-1), average='macro')\n",
    "\n",
    "    def fit(self, X, y):\n",
    "        \"\"\"\n",
    "        Optimize rounding thresholds\n",
    "\n",
    "        :param X: The raw predictions\n",
    "        :param y: The ground truth labels\n",
    "        \"\"\"\n",
    "        loss_partial = partial(self._f1_loss, X=X, y=y)\n",
    "        initial_coef = [1.0 for _ in range(len(set(y)))]\n",
    "        self.coef_ = sp.optimize.minimize(loss_partial, initial_coef, method='nelder-mead')\n",
    "\n",
    "    def predict(self, X, y):\n",
    "        \"\"\"\n",
    "        Make predictions with specified thresholds\n",
    "\n",
    "        :param X: The raw predictions\n",
    "        :param coef: A list of coefficients that will be used for rounding\n",
    "        \"\"\"\n",
    "        X_p = self.coef_['x'] * np.copy(X)\n",
    "\n",
    "        return f1_score(y, np.argmax(X_p, axis=-1), average='macro')\n",
    "\n",
    "    def coefficients(self):\n",
    "        \"\"\"\n",
    "        Return the optimized coefficients\n",
    "        \"\"\"\n",
    "        return self.coef_['x']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
